關於TypeORM設定一對多/多對一參考官網教學
假設新增部門entitiy,使得一個部門有多個使用者
新增部門entity,新增users屬性並設定@OneToMany()
@Entity("Departments")
export class Department {
    @PrimaryGeneratedColumn()
    id: number;
    @Column({
        length: 100,
    })
    depName: string;
    
    @OneToMany(type => User, user => user.dep) // type指定User, 第二個引數是function預設傳入第一個引數的type,這邊需要設定inverse屬性,user entity裡的dep屬性,這個屬性不會存到資料庫
    users: User[];
}
新增Deparment屬性以及foreign key於user.ts
@Entity('My_Users') // 指定table name
export class User {
    @PrimaryGeneratedColumn()
    id: number;
    // @Column為對應的資料庫欄位,或是傳入Column Options物件
    @Column()
    username: string;
   
    ...
    @ManyToOne(type => Department, dep => dep.users
    ,{
        onDelete: 'NO ACTION', // 如果刪除Department,不會一併把UserEntity刪除,另有CASCADE就會
     },
    ) // 設定type為Department,inverse property為Department Entity裡面的users屬性,這個屬性不會存到資料庫
    dep: Department;
    @RelationId((user: User) => user.dep) //指定foreignkey,要設定inverse property
    depId: number;
    
}
建立department.service.ts及depDTO.ts
@Injectable()
export class DepartmentService {
    constructor(
        @InjectRepository(Department) // 注入 typeorm repository
        private readonly depRepo: Repository<Department>,
    ) {}
    
    async addDep(depDto: DepartmentDTO){
        const dep = new Department();
        dep.depName = depDto.depName;
        return await this.depRepo.save(dep);
    }
    async getDepById(id){
        return await this.depRepo.findOne(id);
    }
}
export class DepartmentDTO {
    @IsString()
    @MaxLength(100)
    depName: string;
}
app.controller新增方法
export class AppController {
  constructor(
    private usersService: UsersService,
    private depService: DepartmentService){
  }
  
  ...
  
  @Post('dep')
  @UsePipes(new ValidationPipe({transform:true})) //自動把string轉成int
  addDep(@Body() depDTO: DepartmentDTO){
    return this.depService.addDep(depDTO);
  }
  
}
使用postman新增department
加入depId於userDTO,新增User時指定所屬部門
export class UserDTO {
    
    ...
    @IsNumber()
    depId: number;
}
把app.service與user相關的方法抽出來成為user.service.ts,並修改新增與修改邏輯,
@Injectable()
export class UsersService {
    constructor(
        @InjectRepository(User) // 注入 typeorm repository
        private readonly userRepo: Repository<User>,
        private depService: DepartmentService,
      ){}
      
    
      async addUser(data: UserDTO): Promise<User>{
        const user = new User();
        user.username = data.username;
        user.email = data.email;
        //user.depId  = data.depId; 不能只指定id,必須傳入department物件save的時候才會儲存關聯資料
        user.dep = await this.depService.getDepById(data.depId);
        return await this.userRepo.save(user); // 新增一筆user資料
      }
      
      async getUsers(): Promise<User[]>{
        return await this.userRepo.find({relations: ['dep']}); // relations指定載入關聯屬性,是陣列,可能有多個導覽屬性
      }
    
      async getUserById(id): Promise<User>{
        return await this.userRepo.findOne(id, {relations: ['dep']}); // relations指定載入關聯屬性,是陣列,可能有多個導覽屬性
        // return await this.userRepo.findOneOrFail(id); // 以id搜尋,沒找到會丟出例外
      }
    
      async updateUser(id, data: UserDTO){
        const user = new User();
        user.username = data.username;
        user.email = data.email;
        user.dep = await this.depService.getDepById(data.depId);
        return await this.userRepo.update(id, user); // 用data裡的值更新到資料庫
      }
    
      ...
}
使用postman測試
Github source code每天都好趕
hello您好 我想要請教一個問題
關於這邊//user.depId = data.depId; 不能只指定id,必須傳入department物件save的時候才會儲存關聯資料
想請問一定要傳入department物件才能關聯嗎,這樣做的目的是會優化查詢速度嗎?
如果直接存取data.depId,未來也能用find找到資料嗎?
不知道其中有甚麼差別,希望能幫助解答,謝謝。